---------------------------------------------------------------------------------
  -- Design Name : User Package
  -- File Name   : UserPkg.vhd
  -- Function    : Defines constants and components often used
  -- Authors     : Mirko Francuski  2006/0225
  --               Milos Mihajlovic 2006/0039
  -- School      : University of Belgrade
  --               School for Electrical Engineering
  --               Department for Computer Engineering and Information Theory
  -- Subject     : VLSI Computer Systems
---------------------------------------------------------------------------------

library ieee;
use ieee.std_logic_1164.all;
use ieee.std_logic_signed.all;
use ieee.std_logic_unsigned.all;
use ieee.numeric_std.all;

package UserPkg is

  -- constant definitions
  constant LEN_WORD    : integer := 32;
  constant LEN_REGADDR : integer := 5;
  constant LEN_OPCODE  : integer := 6;
  constant LEN_SP      : integer := 8;
  constant STACK_SIZE  : integer := 2**LEN_SP;

  -- user defined data types
  subtype word32       is std_logic_vector (LEN_WORD    - 1 downto 0);
  subtype word32Ext    is std_logic_vector (LEN_WORD        downto 0);
  subtype regAddr      is std_logic_vector (LEN_REGADDR - 1 downto 0);
  subtype opCode 	     is std_logic_vector (LEN_OPCODE  - 1 downto 0);
  subtype stackAddr	   is std_logic_vector (LEN_SP      - 1 downto 0);
  subtype stackAddrExt is std_logic_vector (LEN_SP          downto 0); --nema -1 zbog ov
  
  
  -- opcodes
  constant OPC_LOAD    : opCode := "000000";
  constant OPC_ADD     : opCode := "000100";
  constant OPC_AND     : opCode := "000010";
  constant OPC_SHL     : opCode := "000110";
  constant OPC_JMP     : opCode := "000001";
  constant OPC_BEQ     : opCode := "000101";
  constant OPC_HALT    : opCode := "000011";
  constant OPC_STORE   : opCode := "100000";
  constant OPC_SUB     : opCode := "100100";
  constant OPC_OR      : opCode := "100010";
  constant OPC_SHR     : opCode := "100110";
  constant OPC_JSR     : opCode := "100001";
  constant OPC_BNQ     : opCode := "100101";
  constant OPC_XOR     : opCode := "010010";
  constant OPC_SAR     : opCode := "010110";
  constant OPC_RTS     : opCode := "010001";
  constant OPC_BGT     : opCode := "010101";
  constant OPC_NOT     : opCode := "110010";
  constant OPC_ROL     : opCode := "110110";
  constant OPC_BLT     : opCode := "110101";
  constant OPC_MOV     : opCode := "001000";
  constant OPC_ADDI    : opCode := "001100";
  constant OPC_ROR     : opCode := "001110";
  constant OPC_PUSH    : opCode := "001001";
  constant OPC_BGE     : opCode := "001101";
  constant OPC_MOVI    : opCode := "101000";
  constant OPC_SUBI    : opCode := "101100";
  constant OPC_POP     : opCode := "101001";
  constant OPC_BLE     : opCode := "101101";
  constant OPC_NOP     : opCode := "111111";
 
  -- components

  -- register
  component GenReg32
    port (
      clk:      in  std_logic;
      ld:       in  std_logic;
      cl:       in  std_logic;
      regIn:    in  word32;
      regOut:   out word32
    );
  end component;
  
  -- register extended with inc and dec
  component GenRegExt32
    port (
      clk     : in  std_logic;
      ld      : in  std_logic;
      inc     : in  std_logic;
      dec     : in  std_logic;
      cl      : in  std_logic;
      regIn   : in  word32;
      regOut  : out word32
    );
  end component;          

  -- comparator
  component GenCmp32 is
    port (
      enable:   in  std_logic;
      in1:      in  word32;
      in2:      in  word32;
      G:        out std_logic := '0';
      E:        out std_logic := '0';
      L:        out std_logic := '0'
    );
  end component;

  -- adder
  component GenAdd32 is
    port (
      in1:      in  word32;
      in2:      in  word32;
      add_out:  out word32 := (others => '0');
      v:        out std_logic := '0';
      c:        out std_logic := '0'
    );
  end component;
  
  -- mux 32b 2to1
  component GenMux32_2 is
    port (
      in1: in word32;
      in2: in word32;
      sel: in std_logic;
      muxOut: out word32
    );
  end component;
  
  -- mux 32b 4to1
  component GenMux32_4 is
    port (
      in1 :    in  word32;
      in2 :    in  word32;
      in3 :    in  word32;
      in4 :    in  word32;
      sel :    in  std_logic_vector(1 downto 0);
      muxOut : out word32
    );
  end component;
  
  -- GenTsbuffer
  component GenTsb is
    port (
      request : in  std_logic;
      datain :  in  word32;
      dataout : out word32
    );
  end component;

  -- mux 5b 2to1
  component IdMux5_2 is
    port (
      in1: in regAddr;
      in2: in regAddr;
      sel: in std_logic;
      muxOut: out regAddr
    );
  end component;
  
    -- instuction split
  component IdInstrSplit is
    port (
      data:     in  word32;
      op:       out opCode;
      rd:       out regAddr;
      rs1:      out regAddr;
      rs2:      out regAddr;
      imm11:    out std_logic_vector(10 downto 0)
    );
  end component;
  
  -- creating control lines
  component IdCtrl is
    port (
      op:           in  opCode;
      addV:         in std_logic;
      addC:         in std_logic;
      addrType:     out std_logic;
      shifts:       out std_logic;
      immType:      out std_logic_vector(1 downto 0);
      immUse:       out std_logic;
      branchCond:   out std_logic;
      branchAlw:    out std_logic
    );
  end component;
  
  -- expanding immidate value
  component IdImmExp is
    port (
      immType:  in  std_logic_vector(1 downto 0);
      rd:       in  regAddr;
      rs2:      in  regAddr;
      imm11:    in  std_logic_vector(10 downto 0);
      imm:      out word32
    );
  end component;
   
  --calculating 
  component IdBranchCalc is
    port (
      enable:   in  std_logic;
      opH:      in  std_logic_vector(2 downto 0); --vishih 3b opCode
      in1:      in  word32;
      in2:      in  word32;
      br_cnd:   out std_logic := '0'
    );
  end component;
  
  -- general purpose registers
  component IdRegs32_32 is
    port (
      clk:      in  std_logic;
      rs1:      in  RegAddr;
      rs2:      in  RegAddr;
      wr:       in  std_logic;
      cl:		    in  std_logic;
      rwr:      in  RegAddr;
      rwr16:    in  std_logic;
      rwr_data: in  word32;
      rs1_data: out word32 := (others => '0');
      rs2_data: out word32 := (others => '0')
    );
  end component;

  -- alu
  component ExMemAlu32 is
    port (
      op:       in opCode;
      in1:      in word32;
      in2:      in word32;
      alu_out:  out word32 := (others => '0');
      n:        out std_logic := '0';
      z:        out std_logic := '0';
      c:        out std_logic := '0';
      v:        out std_logic := '0'
    );
  end component;
  
  -- stack pointer
  component ExMemSP is
    port (
      clk     : in  std_logic;
      cl      : in  std_logic;
      inc     : in  std_logic;
      dec     : in  std_logic;
      spOut   : out stackAddrExt := (others => '0')
    );
  end component;

  component ExMemMemory is
    port (
      clk     : in  std_logic;
      we      : in  std_logic;
      addr    : in  stackAddr;
      dataIn  : in  word32;      
      dataOut : out word32
    );
  end component;
  
  -- stack
  component ExMemStack32_1024 is
    port (
      clk     : in    std_logic;
      cl      : in    std_logic;
      push    : in    std_logic;
      pop     : in    std_logic;
      dataIn  : in    word32;
      stackV  : out   std_logic;
      dataOut : out   word32
    );
  end component;
  
  component ExMemCtrl is
    port (
      stackV      : in  std_logic;
      aluV        : in  std_logic;
      aluN        : in  std_logic;
      aluZ        : in  std_logic;
      aluC        : in  std_logic;
      wr          : in  std_logic;
      op          : in  OpCode;
      rwr         : in  RegAddr;
      r1addr      : in  RegAddr;
      r2addr      : in  RegAddr;
      stackPush   : out std_logic;
      stackPop    : out std_logic;
      aluAMUXSel  : out std_logic;
      aluBMUXSel  : out std_logic;
      stackMUXSel : out std_logic;
      dRd         : out std_logic;
      dWr         : out std_logic;
      workSignal  : in  std_logic
    );
  end component;
   
  component WbCtrl is
  port (
    op:           in  opCode;
    wbSel:        out std_logic_vector(1 downto 0);
    wr:           out std_logic;
    rwr16:        out std_logic;    
    loRts:        out std_logic
  );
  end component;
  
  -- stages
  
  -- if
  component IfStage is
    port (
      clk         : in  std_logic;
      wrkIn       : in  std_logic;
      wrkOut      : out std_logic;
      branchTaken : in  std_logic;
      loRTS       : in  std_logic;
      stall       : in  std_logic;
      reset       : in  std_logic;
      newAddr     : in  word32;
      wbOut       : in  word32;
      newPC       : out word32;
      aiBusReq    : out std_logic;
      aiBUS       : out word32
    );
  end component;
  
  -- R
  component R_If_Id is
    port (
      clk         : in  std_logic;
      wrkIn       : in  std_logic;
      wrkOut      : out std_logic;
      reset       : in  std_logic;
      stall       : in  std_logic;
      newAddrIn   : in  word32;
      newAddrOut  : out word32
    );
  end component;
  
  -- id
  component IdStage is
    port (
      clk         : in  std_logic;
      wrkIn       : in  std_logic;
      wrkOut      : out std_logic;
      newPC       : in  word32;
      DIBus       : in  word32;
      wr          : in  std_logic;
      rwr         : in  regAddr;
      rwr16       : in  std_logic;
      wbData      : in  word32;
      prevOp      : in  opCode;
      prevRdAddr  : in  regAddr;
      reset       : in  std_logic;
      op          : out opCode;
      rdAddr      : out regAddr;
      rs1Addr     : out regAddr;
      rs2Addr     : out regAddr;    
      newAddr     : out word32;
      rs1Data     : out word32;
      rs2Data     : out word32;
      idle        : out std_logic;
      stall       : out std_logic;
      halt        : out std_logic
    );
  end component;
  
  -- R
  component R_Id_ExMem is
    port (
      clk         : in  std_logic;
      wrkIn       : in  std_logic;
      wrkOut      : out std_logic;
      reset       : in  std_logic;
      stall       : in  std_logic;
      idleIn      : in  std_logic;
      idleOut     : out std_logic;
      newAddrIn   : in  word32;
      newAddrOut  : out word32;
      rs1DataIn   : in  word32;
      rs1DataOut  : out word32;
      rs2DataIn   : in  word32;
      rs2DataOut  : out word32;
      opIn        : in  opCode;
      opOut       : out opCode;
      rdAddrIn    : in  RegAddr;
      rdAddrOut   : out RegAddr;      
      r1AddrIn    : in  RegAddr;
      r1AddrOut   : out RegAddr;
      r2AddrIn    : in  RegAddr;
      r2AddrOut   : out RegAddr
    );
  end component;
  
  -- ex+mem
  component ExMemStage is
      port (
      clk         : in  std_logic;
      wrkIn       : in  std_logic;
      wrkOut      : out std_logic;
      idleIn      : in  std_logic;
      reset       : in  std_logic;
      wr          : in  std_logic;
      newAddr     : in  word32;
      rs1Data     : in  word32;
      rs2Data     : in  word32;
      wbData      : in  word32;
      r1addr      : in  RegAddr;
      r2addr      : in  RegAddr;
      rwr         : in  RegAddr;
      rd          : in  RegAddr;
      op          : in  OpCode;
      adBusReq    : out std_logic;
      ddBusReq    : out std_logic;
      dRd         : out std_logic;
      dWr         : out std_logic;
      opOut       : out OpCode;
      rdOut       : out regAddr;
      aluData     : out word32;
      adBus       : out word32;
      ddBus       : out word32;
      stackData   : out word32
    );
  end component;
  
  component R_ExMem_Wb is
    port (
      clk          : in  std_logic;
      reset        : in  std_logic;
      stall        : in  std_logic;
      wrkIn        : in  std_logic;
      wrkOut       : out std_logic;
      aluDataIn    : in  word32;
      aluDataOut   : out word32;
      stackDataIn  : in  word32;
      stackDataOut : out word32;
      rdIn         : in  regAddr;
      rdOut        : out regAddr;
      opIn         : in  opCode;
      opOut        : out opCode  
    );
  end component;
  
  -- wb
  component WbStage is
    port (
      clk         : in  std_logic;
      wrkIn       : in  std_logic;
      wrkOut      : out std_logic;
      op          : in  opCode;
      aluOut      : in  word32;
      DDBus       : in  word32;
      stackOut    : in  word32;
      rd          : in  regAddr;
      wbData      : out word32;
      wr          : out std_logic;
      rwr         : out regAddr;
      rwr16       : out std_logic;
      loRts       : out std_logic   
    );
  end component;
  
  -- cpu
  component CPU is
    port (
      clock   : in     std_logic;
      start   : in     std_logic;
      reset   : in     std_logic;
      diBUS   : in     Word32;
      halt    : out    std_logic;
      iRd     : out    std_logic;
      dRd     : out    std_logic;
      dWr     : out    std_logic;
      aiBUS   : out    Word32 := (others => 'Z');
      adBUS   : out    Word32 := (others => 'Z');
      ddBUS   : inout  Word32 := (others => 'Z')
    );
  end component;
  
end;